package filters

import (
	"crypto/md5"
	"encoding/hex"
	"net/http"
	"strings"

	"cashew.com/cashew_common/configs"
	"cashew.com/cashew_common/constants"
	"cashew.com/cashew_common/utils"
	"github.com/beego/beego/v2/core/logs"
	beecontext "github.com/beego/beego/v2/server/web/context"
)

const (
	SOURCE_TYPE_WEB    = "web"
	SOURCE_TYPE_CLIENT = "client"
)

func FilterSign(ctx *beecontext.Context) {
	isOpen := configs.FilterSignIsOpen

	if isOpen == 0 {
		return
	}

	//限制请求必须是post请求且格式必须是json
	if ctx.Input.Method() != "POST" {
		ctx.Output.SetStatus(http.StatusMethodNotAllowed)
		return
	}

	contentType := ctx.Input.Header("Content-Type")
	logs.Debug("收到请求Content-Type: %s", contentType)
	if !strings.HasPrefix(contentType, "application/json") {
		logs.Warn("收到不支持的Content-Type请求: %s", contentType)
		ctx.Output.SetStatus(http.StatusUnsupportedMediaType)
		return
	}

	body := string(ctx.Input.RequestBody)
	logs.Debug("收到请求ctx.Input.RequestBody: %s", body)
	if body == "" {
		return
	}

	// 获取请求来源
	sourceType := ctx.Input.Header("Source-Type")
	if sourceType == "develop" {
		// 临时测试用 todo 后续删除
		return
	}
	if sourceType == "" || (sourceType != SOURCE_TYPE_WEB && sourceType != SOURCE_TYPE_CLIENT) {
		sourceTypeValidateFail(ctx)
		return
	}

	// 提取 sign 参数
	sign := ctx.Request.Header.Get("Api-Sign")
	logs.Debug("收到请求Api-Sign: %s", sign)
	if sign == "" {
		signValidateFail(ctx)
		return
	}

	// 获取用于签名计算的 key 值
	signKey := configs.FilterSignKey
	if sourceType == SOURCE_TYPE_WEB {
		signKey = configs.FilterWebSignKey
	}

	if signKey == "" {
		logs.Error("服务器异常，签名 key(request_sign::key) 未配置 requestId=%s", ctx.Input.GetData("requestId"))
		signValidateFail(ctx)
		return
	}

	// 计算签名
	logs.Debug("计算签名 body: %s, signKey: %s", body, signKey)
	calculatedSign := GenerateSignature(body, signKey)

	logs.Debug("计算签名结果: %s", calculatedSign)

	// 校验签名
	if calculatedSign != sign {
		logs.Error("签名校验失败，请求签名: %s, 计算签名: %s requestId=%s", sign, calculatedSign, ctx.Input.GetData("requestId"))
		signValidateFail(ctx)
		return
	}
}

// 计算 MD5 签名
func GenerateSignature(body string, signKey string) string {

	body += signKey // 最后加上 signKey

	// 计算 MD5
	hash := md5.Sum([]byte(body))

	//将哈希值转换为十六进制字符串
	return hex.EncodeToString(hash[:])
}

func signValidateFail(ctx *beecontext.Context) {
	res := utils.GenerateResultBody(constants.ERR_REQUEST_SIGN, nil, utils.GetLanguageCode(ctx))
	_ = ctx.Output.JSON(res, false, false)
}

func sourceTypeValidateFail(ctx *beecontext.Context) {
	res := utils.GenerateResultBody(constants.ERR_REQUEST_SOURCE_TYPE, nil, utils.GetLanguageCode(ctx))
	_ = ctx.Output.JSON(res, false, false)
}
